///PHILOTES Source Code.  (C)2012 PhiloLabs
#pragma once


#ifndef __Animation_H__
#define __Animation_H__

#include "OgrePrerequisites.h"
#include "OgreString.h"
#include "OgreIteratorWrappers.h"
#include "OgreAnimable.h"
#include "OgreAnimationTrack.h"
#include "OgreAnimationState.h"

namespace Ogre {
	
	class Animation;
	
	class _OgreExport AnimationContainer
	{
	public:
		
        virtual unsigned short getNumAnimations(void) const = 0;
		
        
        virtual Animation* getAnimation(unsigned short index) const = 0;
		
		
		virtual Animation* getAnimation(const String& name) const = 0;
		
		
		virtual Animation* createAnimation(const String& name, Real length) = 0;
		
		
		virtual bool hasAnimation(const String& name) const = 0;
		
        
        virtual void removeAnimation(const String& name) = 0;
		
	};
    
	class _OgreExport Animation : public MemAlloc_Animation
    {

    public:
        
        enum InterpolationMode
        {
            
            IM_LINEAR,
            
            IM_SPLINE
        };

        
        enum RotationInterpolationMode
        {
            
            RIM_LINEAR,
            
            RIM_SPHERICAL
        };
        
        Animation(const String& name, Real length);
        virtual ~Animation();

        
        const String& getName(void) const;

        
        Real getLength(void) const;

		
		void setLength(Real len);

        
        NodeAnimationTrack* createNodeTrack(unsigned short handle);

		
		NumericAnimationTrack* createNumericTrack(unsigned short handle);

		
		VertexAnimationTrack* createVertexTrack(unsigned short handle, VertexAnimationType animType);

		
        NodeAnimationTrack* createNodeTrack(unsigned short handle, Node* node);

		
		NumericAnimationTrack* createNumericTrack(unsigned short handle, 
			const AnimableValuePtr& anim);

		
		VertexAnimationTrack* createVertexTrack(unsigned short handle, 
			VertexData* data, VertexAnimationType animType);

		
        unsigned short getNumNodeTracks(void) const;

        
        NodeAnimationTrack* getNodeTrack(unsigned short handle) const;

		
		bool hasNodeTrack(unsigned short handle) const;

		
		unsigned short getNumNumericTracks(void) const;

		
		NumericAnimationTrack* getNumericTrack(unsigned short handle) const;

		
		bool hasNumericTrack(unsigned short handle) const;

		
		unsigned short getNumVertexTracks(void) const;

		
		VertexAnimationTrack* getVertexTrack(unsigned short handle) const;

		
		bool hasVertexTrack(unsigned short handle) const;
		
		
        void destroyNodeTrack(unsigned short handle);

		
		void destroyNumericTrack(unsigned short handle);

		
		void destroyVertexTrack(unsigned short handle);

		
        void destroyAllTracks(void);

		
		void destroyAllNodeTracks(void);
		
		void destroyAllNumericTracks(void);
		
		void destroyAllVertexTracks(void);

        
        void apply(Real timePos, Real weight = 1.0, Real scale = 1.0f);

        
		void applyToNode(Node* node, Real timePos, Real weight = 1.0, Real scale = 1.0f);

       
        void apply(Skeleton* skeleton, Real timePos, Real weight = 1.0, Real scale = 1.0f);

        
        void apply(Skeleton* skeleton, Real timePos, float weight,
          const AnimationState::BoneBlendMask* blendMask, Real scale);

		
		void apply(Entity* entity, Real timePos, Real weight, bool software, 
			bool hardware);

        
		void applyToAnimable(const AnimableValuePtr& anim, Real timePos, Real weight = 1.0, Real scale = 1.0f);

        
        void applyToVertexData(VertexData* data, Real timePos, Real weight = 1.0);

		
        void setInterpolationMode(InterpolationMode im);

        
        InterpolationMode getInterpolationMode(void) const;
        
        void setRotationInterpolationMode(RotationInterpolationMode im);

        
        RotationInterpolationMode getRotationInterpolationMode(void) const;

        // Methods for setting the defaults
        
        static void setDefaultInterpolationMode(InterpolationMode im);

        
        static InterpolationMode getDefaultInterpolationMode(void);

        
        static void setDefaultRotationInterpolationMode(RotationInterpolationMode im);

        
        static RotationInterpolationMode getDefaultRotationInterpolationMode(void);

        typedef map<unsigned short, NodeAnimationTrack*>::type NodeTrackList;
        typedef ConstMapIterator<NodeTrackList> NodeTrackIterator;

		typedef map<unsigned short, NumericAnimationTrack*>::type NumericTrackList;
		typedef ConstMapIterator<NumericTrackList> NumericTrackIterator;

		typedef map<unsigned short, VertexAnimationTrack*>::type VertexTrackList;
		typedef ConstMapIterator<VertexTrackList> VertexTrackIterator;

		/// Fast access to NON-UPDATEABLE node track list
        const NodeTrackList& _getNodeTrackList(void) const;

        /// Get non-updateable iterator over node tracks
        NodeTrackIterator getNodeTrackIterator(void) const
        { return NodeTrackIterator(mNodeTrackList.begin(), mNodeTrackList.end()); }
        
		/// Fast access to NON-UPDATEABLE numeric track list
		const NumericTrackList& _getNumericTrackList(void) const;

		/// Get non-updateable iterator over node tracks
		NumericTrackIterator getNumericTrackIterator(void) const
		{ return NumericTrackIterator(mNumericTrackList.begin(), mNumericTrackList.end()); }

		/// Fast access to NON-UPDATEABLE Vertex track list
		const VertexTrackList& _getVertexTrackList(void) const;

		/// Get non-updateable iterator over node tracks
		VertexTrackIterator getVertexTrackIterator(void) const
		{ return VertexTrackIterator(mVertexTrackList.begin(), mVertexTrackList.end()); }

		
		void optimise(bool discardIdentityNodeTracks = true);

        /// A list of track handles
        typedef set<ushort>::type TrackHandleList;

        
        void _collectIdentityNodeTracks(TrackHandleList& tracks) const;

        
        void _destroyNodeTracks(const TrackHandleList& tracks);

		
		Animation* clone(const String& newName) const;
		
        
        void _keyFrameListChanged(void) { mKeyFrameTimesDirty = true; }

        
        TimeIndex _getTimeIndex(Real timePos) const;
		
		
		void setUseBaseKeyFrame(bool useBaseKeyFrame, Real keyframeTime = 0.0f, const String& baseAnimName = StringUtil::BLANK);
		
		bool getUseBaseKeyFrame() const;
		
		Real getBaseKeyFrameTime() const;
		
		const String& getBaseKeyFrameAnimationName() const;
		
		/// Internal method to adjust keyframes relative to a base keyframe (@see setUseBaseKeyFrame) */
		void _applyBaseKeyFrame();
		
		void _notifyContainer(AnimationContainer* c);
		
		AnimationContainer* getContainer();
		
    protected:
        /// Node tracks, indexed by handle
        NodeTrackList mNodeTrackList;
		/// Numeric tracks, indexed by handle
		NumericTrackList mNumericTrackList;
		/// Vertex tracks, indexed by handle
		VertexTrackList mVertexTrackList;
        String mName;

        Real mLength;
		
        InterpolationMode mInterpolationMode;
        RotationInterpolationMode mRotationInterpolationMode;

        static InterpolationMode msDefaultInterpolationMode;
        static RotationInterpolationMode msDefaultRotationInterpolationMode;

        /// Global keyframe time list used to search global keyframe index.
        typedef vector<Real>::type KeyFrameTimeList;
        mutable KeyFrameTimeList mKeyFrameTimes;
        /// Dirty flag indicate that keyframe time list need to rebuild
        mutable bool mKeyFrameTimesDirty;

		bool mUseBaseKeyFrame;
		Real mBaseKeyFrameTime;
		String mBaseKeyFrameAnimationName;
		AnimationContainer* mContainer;

		void optimiseNodeTracks(bool discardIdentityTracks);
		void optimiseVertexTracks(void);

        /// Internal method to build global keyframe time list
        void buildKeyFrameTimeList(void) const;
    };

	
	
}


#endif

